﻿#region Copyright(c) 2006 ZO, All right reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2006 ZO, All right reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1.  Redistribution of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//   2.  Redistribution in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//   3.  The name of the author may not be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// -----------------------------------------------------------------------------
#endregion


#region Using directives

using System;
using System.IO;
using ZO.SmartCore.IO;
using ZO.SmartCore.Xml;
using ArgumentException= ZO.SmartCore.Core.ArgumentException;
using ArgumentNullException= ZO.SmartCore.Core.ArgumentNullException;

#endregion

namespace ZO.SmartCore.Configuration
{
    /// <summary>
    /// Provides support for reading or writing configuration sections.
    /// </summary>
    /// <typeparam name="TFormatter">Represent Configuration Format</typeparam>
    /// <typeparam name="TProvider">Represent Configuration Provider</typeparam>
    public class ConfigurationSettings<TProvider, TFormatter> 
        where TProvider : IConfigurationProvider, new()
        where TFormatter : IConfigurationFormat, new()
    {

        #region Constructors
      
        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurationSettings{TProvider, TFormatter}"/> class.
        /// </summary>
        public ConfigurationSettings()
        {
            //this._Format = ConfigurationFormatType.Xml;
            this._Formatter = Activator.CreateInstance<TFormatter>();
            this._Provider = Activator.CreateInstance<TProvider>();
            //this._Type = ConfigurationProviderType.File;
            //this.provider = new FileConfigurationProvider();
        } // ConfigurationSettings


        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurationSettings{TProvider, TFormatter}"/> class.
        /// </summary>
        /// <param name="formatter">The format of the file.</param>
        /// <param name="provider">storage provider.</param>
        public ConfigurationSettings(TFormatter formatter, TProvider provider)
        {
            if (formatter == null)
            {
                throw new ArgumentNullException("formatter");
            }

            if (provider == null)
            {
                throw new ArgumentNullException("formatter");
            }

            this._Formatter = formatter;
            this._Provider = provider;

           
        } // ConfigurationSettings
        #endregion

        #region Destructor

        #endregion

        #region Fields
        private string _FileName;
        private TFormatter _Formatter;

        private TProvider _Provider;



        #endregion

        #region Events

        #endregion

        #region Operators

        #endregion

        #region Properties

        /// <summary>
        /// Get The Name of Format used by the Formatter
        /// </summary>
        /// <value>format name.</value>
        public string FormatName
        {
            get
            {
                return this._Formatter.Name;
            }
        }

        /// <summary>
        /// Get The Name of Format used by the Provider
        /// </summary>
        /// <value>provider name.</value>
        public string ProviderName
        {
            get
            {
                return this.Provider.Name;
            }
        }

        /// <summary>
        /// Gets the configuration file Formatter.
        /// </summary>
        /// <value>The formatter.</value>
        public TFormatter Formatter
        {
            get { return _Formatter; }
        }

        /// <summary>
        /// Gets the configuration file provide.
        /// </summary>
        /// <value>The type.</value>
        public TProvider Provider
        {
            get { return _Provider; }
        }

        /// <summary>
        /// Gets the Sections to add settings.
        /// </summary>
        /// <value>The configs Sections.</value>
        public Section ConfigSection
        {
            get
            {
                if (this._Formatter != null)
                {
                    return _Formatter.DefaultSection;
                }
                return null;
            }
        }

        /// <summary>
        /// Gets the contents currently written to config File.
        /// </summary>
        /// <value>The contents.</value>
        public StringStream Contents
        {
            get
            {
                return this.Formatter.Write();
            }
        }
        #endregion

        #region Methods

        /// <summary>
        /// Gets the XML document from provider.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <returns></returns>
        public Document GetXmlDocument(string file)
        {
            return this._Provider.GetXmlDocument(file);
        }

        /// <summary>
        /// Saves the XML document in provider space.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="xmlDoc">The XML doc.</param>
        public void SaveXmlDocument(string file, Document xmlDoc)
        {
            this._Provider.SaveXmlDocument(file, xmlDoc);
        }


        /// <summary>
        /// Opens the specified file name.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public void Open(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            } // if

            if (fileName.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException();
            } // if


            this._FileName = fileName;
            StringStream str = this._Provider.Load(fileName);
            this._Formatter.Read(str);


        } // Open


        /// <summary>
        /// Saves the specified file name.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public void SaveFile(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }
            new FileConfigurationProvider().Save(fileName, this._Formatter.Write());
        } // Save

        /// <summary>
        /// Saves this specified configuration.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public void Save(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }
            this._Provider.Save(fileName, this._Formatter.Write());
        } // Save


        /// <summary>
        /// Saves this specified configuration.
        /// </summary>
        public void Save()
        {
            if (String.IsNullOrEmpty(_FileName))
            {
                throw new ArgumentNullException("fileName");
            }

            this._Provider.Save(this._FileName, this._Formatter.Write());
        } // Save

        /// <summary>
        /// Saves the specified file name.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="provider">The storage provider used to Save The File.</param>
        public void Save(string fileName, TProvider provider)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }

            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            provider.Save(fileName, this._Formatter.Write());
        } // Save   

        /// <summary>
        /// Creates the directory.
        /// </summary>
        /// <param name="directory">The path of the directory to create.</param>
        public void CreateDirectory(string directory)
        {
            if (String.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException("directory");
            } // if

            this._Provider.CreateDirectory(directory);
        }


        /// <summary>
        /// Get Whether specified file exists
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>true if file exists else false</returns>
        public bool FileExists(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                return false;
            } // if
            return this._Provider.FileExists(fileName);

        }

        /// <summary>
        /// Get Whether specified directory exists
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <returns>true if directory exists else false</returns>
        public  bool DirectoryExists(string directoryName)
        {
            if (String.IsNullOrEmpty(directoryName))
            {
                return false;
            } // if
            return this._Provider.DirectoryExists(directoryName);
        }


        /// <summary>
        /// Deletes the directory.
        /// </summary>
        /// <param name="directory">The directory.</param>
        public void DeleteDirectory(string directory)
        {
            if (String.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException("directory");
            } // if
            this._Provider.DeleteDirectory(directory);
        } // DeleteDirectory


        /// <summary>
        /// Gets all the files names in specified folder.
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <returns>All files name in specified folder</returns>
        public string[] GetFilesNames(string directoryName)
        {
            return this._Provider.GetFilesNames(directoryName);

        }


        /// <summary>
        /// Gets all the files names in specified folder.
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <param name="searchPattern">The search string to match against the names of files in path.</param>
        /// <returns>All files name in specified folder</returns>
        public string[] GetFilesNames(string directoryName, string searchPattern)
        {
            return this._Provider.GetFilesNames(directoryName, searchPattern);
        }

        /// <summary>
        /// Deletes the File.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public void DeleteFile(string fileName)
        {
            this._Provider.DeleteFile(fileName);
        }

        #endregion
    }
}
